package com.jframework.module.usps.utils;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;

import java.io.IOException;
import java.net.URL;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.wutka.jox.*;
import com.wutka.dtd.*;

/* 
 * This is utility class for reading and write XML from bean classes. 
 * It uses JOX api. 
 */
public class BeanXMLMapping 
{
    static Log log = LogFactory.getLog(BeanXMLMapping.class);
    URL dtdURL	   = null;
    DTD dtd	   = null;

    /**
     *  Retrieves a bean object for the
     *  received XML and matching bean class
     */
    public Object fromXML(String xml, Class className)
    {
        if (log.isDebugEnabled()) 
            log.debug("Entering fromXML()");
        
	ByteArrayInputStream xmlData = new ByteArrayInputStream(xml.getBytes());
        JOXBeanInputStream joxIn = new JOXBeanInputStream(xmlData);

        try
        {
            return joxIn.readObject(className);
        } catch (IOException exc)
        {
            log.error("Error in binding class "+className+" from XML",exc);
            return null;
        } finally
        {
            try
            {
                xmlData.close();
                joxIn.close();
            } catch (Exception e)
            {
                log.error("JOX Exception in closing jox, xmldata", e);
            }
        }

    }
    
    public String toXML(URL dtdURL, Object bean)
    {
	this.setDtdURL(dtdURL);
	return this.toXML(bean);
    }

    public String toXML(Object bean) 
    {	
        if (log.isDebugEnabled()) 
            log.debug("Entering toXML()");
	ByteArrayOutputStream xmlData = new ByteArrayOutputStream();
        JOXBeanOutputStream joxOut = null;
        try
        {
          if (null != this.dtd)
            joxOut = new JOXBeanOutputStream(dtd, xmlData, null);
          else
            joxOut = new JOXBeanOutputStream(xmlData, null);        
            joxOut.writeObject(beanName(bean), bean);
            return this.fixXML(xmlData.toString());
        } catch (IOException exc)
        {
            log.error("Error in converting "+bean.getClass().getName()+" to XML", exc);
            return null;
        } finally
        {
            try
            {
                xmlData.close();
                joxOut.close();
            } catch (Exception e)
            {
                e.printStackTrace();
            }
        }
    }

    /*
     * Removes First line of XML
     * which is <?xml ..... ?>
     */
    private String fixXML(String string) 
    {
       String removedXMLDecl = (string.lastIndexOf("?>") != -1)?
	string.substring(string.lastIndexOf("?>")+2):
	string;
      String finalXML = removedXMLDecl.replaceAll("\r", "").replaceAll("\n", "");
      return finalXML;
    }


    /**
     *  Find out the bean class name
     */
    private String beanName(Object bean)
    {
        String fullClassName = bean.getClass().getName();
        String classNameTemp = fullClassName.substring(
                fullClassName.lastIndexOf(".") + 1,
                fullClassName.length()
                );
        return classNameTemp.substring(0, 1)
                 + classNameTemp.substring(1);
    }

    /**
     * @return the dtdURL
     */
    public URL getDtdURL() {
	
      
        return dtdURL;
    }

    /**
     * @param dtdURL the dtdURL to set
     */
    public void setDtdURL(URL dtdURL) {
	
        this.dtdURL = dtdURL;
	DTDParser dtdParser;
	try 
	{
	   dtdParser = new DTDParser(this.dtdURL, false);	
           this.dtd = dtdParser.parse(false);
	} catch (IOException e) 
	{
	   log.error("Error in parsing DTD URL for USPS", e);
	   this.dtd = null;
	}
    }

    /**
     * @return the dtd
     */
    public DTD getDtd() {
        return dtd;
    }

    /**
     * @param dtd the dtd to set
     */
    public void setDtd(DTD dtd) {
        this.dtd = dtd;
    }

}
